This script reads in both PBMC and Liver Seurat objects, and generates select figures used in the manuscript.

Prepare objects

Load libraries

library(Seurat)
Loading required package: SeuratObject
Loading required package: sp

Attaching package: ‘SeuratObject’

The following objects are masked from ‘package:base’:

    intersect, saveRDS

Loading Seurat v5 beta version 
To maintain compatibility with previous workflows, new Seurat objects will use the previous object structure by default
To use new Seurat v5 assays: Please run: options(Seurat.object.assay.version = 'v5')
library(scClustViz)
Loading required package: shiny
library(ggplot2)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(rcartocolor)
library(SeuratWrappers)

Read in liver map

sobj <- readRDS("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/dropletQC_filtered/allIntegrated_cca_kanchor5_noBiopsyHeps_dropletQCFiltered.RDS")
res <- "integrated_snn_res.1.4"
Idents(sobj) <- res
tissue <- "liver"

Read in PBMC map

load("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/no_dropletQC/integrated_PBMC_cca_kanchor5_scClustViz.RData")
sobj <- scSeurat
res <- "integrated_snn_res.0.6"
Idents(sobj) <- res
tissue <- "PBMC"

Visualization of metadata

UMAP with no cluster numbers

plot <- DimPlot(sobj, label = FALSE) & NoLegend()
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_clusters_noLabels.pdf", sep = ""))
plot
dev.off()
png 
  2 

UMAP with cluster numbers

plot <- DimPlot(sobj, label = TRUE)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_clusters_labels.pdf", sep = ""))
plot
dev.off()
png 
  2 

Map with SCINA-generated cell-type labels

DimPlot(sobj, group.by = "scina_labels_refined", label = TRUE) & NoLegend()

Map with general cell-type labels for paper

plot <- DimPlot(sobj, group.by = "general_cell_labels",
        label = TRUE, repel = TRUE) +
  ggtitle(NULL)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_general_cell_labels.pdf", sep = ""),
    height = 7,
    width = 9)
plot
dev.off()
png 
  2 

Map grouping by general cell type labels but with no labels on plot

plot <- DimPlot(sobj, group.by = "general_cell_labels") +
  ggtitle(NULL) &
  NoLegend()
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_general_cell_labels_noLabels.pdf", 
          sep = ""))
plot
dev.off()
png 
  2 

Map with original identities

plot <- DimPlot(sobj, group.by = "orig.ident",
        cols = carto_pal(length(levels(as.factor(sobj$orig.ident))), "Safe")) +
  ggtitle(NULL)
plot
pdf(paste("./figures/", tissue, "/", tissue, "_UMAP_orig_idents.pdf", 
          sep = ""))
plot
dev.off()
png 
  2 

Barplot with original identities on a cluster-level grouping:

# Meta data to plot:
df <- sobj@meta.data
# Check what column the cluster identities are in
col <- which(colnames(df) == res)
# Order clusters
df[,col] <- factor(Idents(sobj),
                             levels = c(sort(as.numeric(levels(Idents(sobj))))))
# Basic plot of clusters by replicate
ggplot(df, aes(x = get(res), fill = orig.ident)) +
  geom_bar() +
  theme(axis.text = element_text(size = 7))

# Plot as proportion or percentage of cluster
ggplot(df, aes(x = get(res), fill = orig.ident)) +
  geom_bar(position = "fill") +
  theme(axis.text = element_text(size = 7))

Barplot with original identities on a grouped by general cell labels:

df <- sobj@meta.data
plot1 <- ggplot(df, aes(x = general_cell_labels, fill = orig.ident)) +
  geom_bar() +
  scale_fill_carto_d(name = NULL, palette = "Safe") +
  theme_bw() +
  theme(axis.text = element_text(size = 8),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank()) +
  ylab("Number of cells")
plot1
pdf(paste("./figures/", tissue, "/", tissue, "_barplot_orig_ident_counts.pdf", 
          sep = ""))
plot1
dev.off()
png 
  2 

# Plot as proportion or percentage of cluster
plot2 <- ggplot(df, aes(x = general_cell_labels, fill = orig.ident)) +
  geom_bar(position = "fill") +
  scale_fill_carto_d(name = NULL, palette = "Safe") +
  theme_bw() +
  theme(axis.text = element_text(size = 8),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        axis.title.x = element_blank()) +
  ylab("Proportion of cells")
plot2
pdf(paste("./figures/", tissue, "/", tissue, "_barplot_orig_ident_proportions.pdf", 
          sep = ""))
plot2
dev.off()
png 
  2 

Dotplots

Generate dotplot with specific markers

DotPlot(sobj,
        assay = "SCT",
        features = c("PTPRC", "CALCRL", "NKG7", "CD3E", "MARCO", "LYZ-1", "CD19", "MS4A1", "STAB2")
        ) +
  ggtitle("Select features for liver map")

Heatmaps

Calculate markers for general cell labels then reset resolution

Idents(sobj) <- "general_cell_labels"
sobj_markers <- RunPrestoAll(sobj, 
                             only.pos = TRUE, 
                             min.pct = 0.25, 
                             logfc.threshold = 0.25)
Calculating cluster B cells
Calculating cluster Lymphocytes 3
Calculating cluster Monocytes 1
Calculating cluster Erythrocytes
Calculating cluster Lymphocytes 1
Calculating cluster Monocytes 2
Calculating cluster Lymphocytes 2
Calculating cluster Lymphocytes 5
Calculating cluster Monocytes 3
Calculating cluster Monocytes 4
Calculating cluster Plasma B cells
Calculating cluster Unknown
Calculating cluster Mast cells
Calculating cluster Lymphocytes 4
Calculating cluster Hematopoietic stem cells
Calculating cluster Megakaryocytes
sobj_markers %>%
    group_by(cluster) %>%
    slice_max(n = 2, order_by = avg_log2FC)
Idents(sobj) <- res

Save markers

groups = "general_cell_labels"
write.table(sobj_markers,
            file = paste("./figures/", tissue, "/",
                         tissue, "_markers_", groups, ".tsv", 
                         sep = ""),
            quote = FALSE,
            sep = "\t",
            row.names = FALSE,
            col.names = TRUE)

Generate heatmap with top 5 markers grouping by general cell types

# Remove mikado genes from marker list
sobj_markers <- sobj_markers[grep("mikado", rownames(sobj_markers), invert = TRUE),]
sobj_markers %>%
    group_by(cluster) %>%
    top_n(n = 5, wt = avg_log2FC) -> top
# If liver, select fewer cells
if (tissue == "liver") {
  cells <- sample(colnames(sobj), size = 30000)
} else if (tissue == "PBMC") {
  cells <- colnames(sobj)
}
DoHeatmap(sobj, features = top$gene, group.by = "general_cell_labels", size = 3, 
          angle = 90, cells = cells) +
  NoLegend() +
  theme(text = element_text(size = 7))

Make PDF of heatmap

groups <- "general_cell_labels"
pdf(paste("./figures/", tissue, "/", tissue, "_heatmap_", groups, ".pdf", sep = ""),
    height = 11,
    width = 7)
DoHeatmap(sobj, features = top$gene, group.by = "general_cell_labels", size = 2, 
          angle = 90, cells = cells) +
  NoLegend() +
  theme(text = element_text(size = 7))
dev.off()
null device 
          1 

Feature plots

Make specific plots with specific genes. The genes we are interested in include: PTPRC, CALCRL, NKG7, CD3E, MARCO, LYZ, CD19, MS4A1, STAB2, ALB, CD4, CD8A, CLEC4G, CD5L, C1QB, ACTA2, VWF, IGLL5, CD68. Can also plot in italics.

geneCode <- "sct_LYZ-1" # Woodchuck-specific nomenclature for this genome
gene <- "LYZ"
mapType <- "Liver"
FeaturePlot(sobj, features = geneCode) +
  ggtitle(paste(gene, "-", mapType, "map"))

FeaturePlot(sobj, features = geneCode) +
  ggtitle(bquote(~italic(.(gene))))

Another version of the feature plot that outputs genes in italics

if (tissue == "PBMC") {
 geneCodes <- c("sct_PTPRC","sct_NKG7","sct_CD14",
               "sct_CD3E","sct_MARCO","sct_LYZ-1",
               "sct_CD19","sct_MS4A1","sct_STAB2",
               "sct_CD4","sct_CD8A", "sct_XCL1;XCL2",
               "sct_CD5L","sct_C1QB", "sct_LEF1",
               "sct_ACTA2","sct_VWF","sct_IGLL5-1",
               "sct_CD68","sct_FCGR3A;FCGR3B","sct_TOP2A")
 genes <- c("PTPRC","NKG7","CD14","CD3E","MARCO","LYZ",
           "CD19","MS4A1","STAB2","CD4","CD8A", "XCL1;XCL2",
           "CD5L","C1QB","LEF1","ACTA2","VWF","IGLL5","CD68",
           "FCGR3A;FCGR3B","TOP2A") 
} else if (tissue == "liver") {
  geneCodes <- c("sct_Ptprc","sct_CALCRL","sct_NKG7",
                 "sct_CD3E","sct_MARCO","sct_LYZ-1",
                 "sct_CD19","sct_MS4A1","sct_STAB2",
                 "sct_ALB-1","sct_CD4","sct_CD8A",
                 "sct_CLEC4G","sct_CD5L","sct_C1QB",
                 "sct_ACTA2","sct_VWF","sct_IGLL5-1",
                 "sct_CD68","sct_XCL1;XCL2","sct_LEF1",
                 "sct_RSPO3","sct_MECOM")
  genes <- c("PTPRC","CALCRL","NKG7","CD3E","MARCO","LYZ",
             "CD19","MS4A1","STAB2","ALB","CD4","CD8A",
             "CLEC4G","CD5L","C1QB","ACTA2","VWF","IGLL5","CD68",
             "XCL1;XCL2","LEF1","RSPO3","MECOM") 
}
for(num in 2:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Cell-population-specific markers

Plot marker genes for specific cell populations

Endothelial cells:

geneCodes <- c("sct_STAB2","sct_ITGA1","sct_CD55","sct_LYVE1",
               "sct_CD34","sct_VWF","sct_IFITM3;IFITM2;IFITM1","sct_RSPO3",
               "sct_MECOM","sct_Mecom","sct_CALCRL","sct_LOC114089654",
               "sct_RAMP2","sct_BST2","sct_CLEC4G","sct_CTSV;CTSL",
               "sct_STAB1","sct_PLAC9","sct_PECAM1","sct_WNT2",
               "sct_MYL6","sct_NR2F2")
genes <- c("STAB2","ITGA1","CD55","LYVE1",
           "CD34","VWF","IFITM3","RSPO3",
           "MECOM","Mecom","CALCRL","LOC114089654",
           "RAMP2","BST2","CLEC4G","CTSV;CTSL",
           "STAB1","PLAC9","PECAM1","WNT2",
           "MYL6","NR2F2") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Lymphocytes:

geneCodes <- c("sct_CD3D","sct_CD3E","sct_CD8A","sct_NKG7",
               "sct_KLRD1","sct_KLRB1","sct_GZMA","sct_LEF1",
               "sct_IL7R-1","sct_EOMES","sct_TIGIT","sct_XCL1;XCL2",
               "sct_TOX","sct_CTLA4","sct_CD4","sct_GZMK")
genes <- c("CD3D","CD3E","CD8A","NKG7",
           "KLRD1","KLRB1","GZMA","LEF1",
           "IL7R","EOMES","TIGIT","XCL1;XCL2",
           "TOX","CTLA4","CD4","GZMK") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Mesenchyme:

geneCodes <- c("sct_HHIP","sct_COL1A2","sct_COL3A1","sct_IGFBP7",
               "sct_IGFBP3","sct_DCN","sct_COL1A1","sct_SPARC",
               "sct_RBP1", "sct_CALCRL")
genes <- c("HHIP","COL1A2","COL3A1","IGFBP7",
           "IGFBP3","DCN","COL1A1","SPARC",
           "RBP1","CALCRL") 
for(num in 1:length(geneCodes)) {
  plot <- FeaturePlot(sobj,
                      features = geneCodes[num]) +
    ggtitle(bquote(~italic(.(genes[num]))))
  print(plot)
  pdf(paste("./figures/", tissue, "/", tissue, "_", genes[num], "_UMAP.pdf", sep = ""))
  print(plot)
  dev.off()
}

Look at zonation gene signatures:

cv_genes <- c("FETUB","HMGCS1","CYP2E1","GLUD1;GLUD2","CYP1A2",
              "RGN","INMT","COMT","FDPS","SPR-1")
cv_genes
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      
pp_genes <- c("Saa2;Saa1-1","HAMP","APOA1","APOC2","CRYL1",
              "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B","MT-ATP6","UROC1",
              "APOA2","MT-CO3")
pp_genes
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       

Correlation plots

Generate heatmaps comparing woodchuck clusters with various datasets

Setup for all correlations

First, set up whatever woodchuck dataset I am working with by reading in the ortholog table, choosing whether the orthologs to use are human, mouse, or woodchuck, and calculating the average expression for each cluster. The output of this section is the scaled cluster gene-expression matrix

groups <- "general_cell_labels"
# Read in ortholog table
geneNameTable <- read.table("~/Dropbox/Zoe/scf_version/make_gtf/orthofinder_sc2/homologene/collectedOrthofinderPairings.tsv",
                            sep = "\t",
                            header = TRUE)
woodchuckClusterAverages <- AverageExpression(sobj,
                                              assays = "SCT",
                                              slot = "scale.data",
                                              group.by = groups)
# Scale data
woodchuckClusterAverages$SCT <- na.omit(t(scale(t(as.matrix(woodchuckClusterAverages$SCT)))))
# Grab gene names from Seurat object
uniqueHier <- row.names(woodchuckClusterAverages$SCT)
uniqueHier <- as.data.frame(uniqueHier)
# Bind with geneNameTable to get correct order (notice uniqueHier is on left)
newNames <- dplyr::left_join(uniqueHier, geneNameTable, by = "uniqueHier")
# Get orthologs from either mouse or human
species <- "human"
if (species == "human") {
  # If human one-to-one ortho has NA, replace with mikado_final_sc2_stringent_noMito_protein column
  # This is to avoid and potential mistakes in recognizing things it shouldn't be recognizing
  newNames$speciesOneToOne <- ifelse(is.na(newNames$humanOneToOne), newNames$uniqueHier, newNames$humanOneToOne)
} else if (species == "mouse") {
  newNames$speciesOneToOne <- ifelse(is.na(newNames$mouseOneToOne), newNames$uniqueHier, newNames$mouseOneToOne)
} else if (species == "woodchuck") {
  newNames$speciesOneToOne <- newNames$uniqueHier
}
# Grab dataframe
woodchuckClusterAverages <- woodchuckClusterAverages$SCT
# Replace names with one-to-one orthologue of particular species
row.names(woodchuckClusterAverages) <- newNames$speciesOneToOne
# Make sure formatted correctly
woodchuckClusterAverages <- as.data.frame(woodchuckClusterAverages)
# Order by gene name
woodchuckClusterAverages <- woodchuckClusterAverages[order(row.names(woodchuckClusterAverages)),]
# Sanity check
head(woodchuckClusterAverages)

Dataset-specific setup

Correlation of woodchuck PBMCs with human 68k PBMC dataset from 10X Genomics

# Sanity check
head(allCellsMatrix)
       Activated CD8+ Naive CD8+ Memory and Reg T Naive CD4+          NK       CD8+          B
42430      -0.7290166 -1.4467216      -0.19073790 -0.4832807  0.02379348 -0.8928406 -0.2258430
42431      -0.2300094 -0.7300300      -0.26479348 -0.7995981 -0.18652940 -0.3474056 -0.6952459
42618      -0.1212209 -0.6309294      -0.09745206 -0.4354971 -0.36419075 -0.8527715 -0.3826776
A4GALT     -0.4058024 -1.0280327      -0.68648235 -0.4734361 -0.11159565 -0.5478332 -0.1352675
AATK       -1.0033368 -0.9033733      -0.11847519 -1.0810861 -0.10366579 -0.4257702 -0.2369504
ABCA1      -0.6939429 -1.0596759      -0.79368826 -0.8411861 -0.88868386 -0.1144697  0.6312458
       Megakaryocytes Monocytes and Dendritic B, Dendritic, T
42430        1.314882              1.50210970       1.1276549
42431        2.578802              0.03087083       0.6439395
42618        2.691420             -0.14763062       0.3409502
A4GALT       2.062829             -0.23671805       1.5623391
AATK         1.958543              1.15513309       0.7589817
ABCA1        1.186970              1.02547753       1.5479533

Correlation of woodchuck liver with human liver dataset from MacParland et al. (2018)

Correlation of woodchuck liver with human liver dataset from Aizarani et al.

allCellsMatrix <- allCellsMatrix[,as.character(sort(as.numeric(colnames(allCellsMatrix))))]
# Rename columns to be more meaningful (not totally confident I got all correct)
colnames(allCellsMatrix) <- c('NK, NKT and T cells (1)',
                              'Kupffer cells (2)',
                              'NK, NKT and T cells (3)',
                              'EPCAM+ cells and cholangiocytes (4)',
                              'NK, NKT and T cells (5)',
                              'Kupffer cells (6)',
                              'EPCAM+ cells and cholangiocytes (7)',
                              'B cells (8)',
                              'Liver sinusoidal endothelial cells (9)',
                              'Macrovascular endothelial cells (10)',
                              'Hepatocytes (11)',
                              'NK, NKT and T cells (12)',
                              'Liver sinusoidal endothelial cells (13)',
                              'Hepatocytes (14)',
                              'Other endothelial cells (15)',
                              'Other (16)',
                              'Hepatocytes (17)',
                              'NK, NKT and T cells (18)',
                              'NK, NKT and T cells (19)',
                              'Liver sinusoidal endothelial cells (20)',
                              'Macrovascular endothelial cells (21)',
                              'B cells (22)',
                              'Kupffer cells (23)',
                              'EPCAM+ cells and cholangiocytes (24)',
                              'Kupffer cells (25)',
                              'Other endothelial cells (26)',
                              'Other (27)',
                              'NK, NKT and T cells (28)',
                              'Macrovascular endothelial cells (29)',
                              'Hepatocytes (30)',
                              'Kupffer cells (31)',
                              'Macrovascular endothelial cells (32)',
                              'Stellate cells and myofibroblasts (33)',
                              'B cells (34)',
                              'Other endothelial cells (35)',
                              'Other (36)',
                              'Other (37)',
                              'B cells (38)',
                              'EPCAM+ cells and cholangiocytes (39)')
# Order by row name
allCellsMatrix <- allCellsMatrix[order(row.names(allCellsMatrix)),]
# Sanity check
head(allCellsMatrix)

speciesData <- "aizarani"

Correlation of woodchuck liver with woodchuck PBMCs. For this correlation, read in the woodchuck liver dataset at the beginning of this script and then read in the woodchuck PBMCs below

groups <- "general_cell_labels"
# Start with liver and read in woodchuck PBMCs again
load("~/Dropbox/Zoe/scf_version/analysis/healthy_sc/seurat_objects/no_dropletQC/integrated_PBMC_cca_kanchor5_scClustViz.RData")
Idents(scSeurat) <- "integrated_snn_res.0.6"
# Find cluster averages
pbmcClusterAverages <- AverageExpression(scSeurat,
                                         assays = "SCT",
                                         slot = "scale.data",
                                         group.by = groups)
pbmcClusterAverages <- as.data.frame(na.omit(t(scale(t(as.matrix(pbmcClusterAverages$SCT))))))
# Order by row name
allCellsMatrix <- pbmcClusterAverages[order(row.names(pbmcClusterAverages)),]
speciesData <- "PBMC"

Output plots for all correlations

# Now find intersecting genes
matches <- intersect(row.names(allCellsMatrix),
                     row.names(woodchuckClusterAverages))
# Look at how many genes matched
length(matches)
[1] 165
# Make new matrices with only matching gene names
toCor <- allCellsMatrix[matches,]
woodchuckAveragesCor <- woodchuckClusterAverages[matches,]
# Do Pearson
pearVal <- cor(toCor, woodchuckAveragesCor, method = "pearson")
heatmap(pearVal)
        #main = paste("Pearson correlation of", speciesData, "vs", woodchuckData),
        #xlab = woodchuckData,
        #ylab = speciesData)
        #margins = c(6,11))
#Rowv = NA,
#Colv = NA)
pdf(paste("./figures/", tissue, "/", tissue, "_", speciesData, "_PearsonCor.pdf", sep = ""),
    height = 13, width = 13)
heatmap(pearVal, margins = c(13,13))
dev.off()
png 
  2 

# Do Spearman
spearVal <- cor(toCor, woodchuckAveragesCor, method = "spearman")
heatmap(spearVal)
        #main = paste("Spearman correlation of", speciesData, "vs", woodchuckData),
        #xlab = woodchuckData,
        #ylab = speciesData)
        #margins = c(6,11))
#Rowv = NA,
#Colv = NA)
pdf(paste("./figures/", tissue, "/", tissue, "_", speciesData, "_SpearmanCor.pdf", sep = ""),
    height = 13, width = 13)
heatmap(spearVal, margins = c(13,13))
dev.off()
png 
  2 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBzY3JpcHQgcmVhZHMgaW4gYm90aCBQQk1DIGFuZCBMaXZlciBTZXVyYXQgb2JqZWN0cywgYW5kIGdlbmVyYXRlcyBzZWxlY3QgZmlndXJlcyB1c2VkIGluIHRoZSBtYW51c2NyaXB0LgoKIyMgUHJlcGFyZSBvYmplY3RzCgpMb2FkIGxpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHNjQ2x1c3RWaXopCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShyY2FydG9jb2xvcikKbGlicmFyeShTZXVyYXRXcmFwcGVycykKYGBgCgpSZWFkIGluIGxpdmVyIG1hcAoKYGBge3J9CnNvYmogPC0gcmVhZFJEUygifi9Ecm9wYm94L1pvZS9zY2ZfdmVyc2lvbi9hbmFseXNpcy9oZWFsdGh5X3NjL3NldXJhdF9vYmplY3RzL2Ryb3BsZXRRQ19maWx0ZXJlZC9hbGxJbnRlZ3JhdGVkX2NjYV9rYW5jaG9yNV9ub0Jpb3BzeUhlcHNfZHJvcGxldFFDRmlsdGVyZWQuUkRTIikKcmVzIDwtICJpbnRlZ3JhdGVkX3Nubl9yZXMuMS40IgpJZGVudHMoc29iaikgPC0gcmVzCnRpc3N1ZSA8LSAibGl2ZXIiCmBgYAoKUmVhZCBpbiBQQk1DIG1hcAoKYGBge3J9CmxvYWQoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvaGVhbHRoeV9zYy9zZXVyYXRfb2JqZWN0cy9ub19kcm9wbGV0UUMvaW50ZWdyYXRlZF9QQk1DX2NjYV9rYW5jaG9yNV9zY0NsdXN0Vml6LlJEYXRhIikKc29iaiA8LSBzY1NldXJhdApyZXMgPC0gImludGVncmF0ZWRfc25uX3Jlcy4wLjYiCklkZW50cyhzb2JqKSA8LSByZXMKdGlzc3VlIDwtICJQQk1DIgpgYGAKCiMjIFZpc3VhbGl6YXRpb24gb2YgbWV0YWRhdGEKClVNQVAgd2l0aCBubyBjbHVzdGVyIG51bWJlcnMKCmBgYHtyfQpwbG90IDwtIERpbVBsb3Qoc29iaiwgbGFiZWwgPSBGQUxTRSkgJiBOb0xlZ2VuZCgpCnBsb3QKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9VTUFQX2NsdXN0ZXJzX25vTGFiZWxzLnBkZiIsIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpVTUFQIHdpdGggY2x1c3RlciBudW1iZXJzCgpgYGB7cn0KcGxvdCA8LSBEaW1QbG90KHNvYmosIGxhYmVsID0gVFJVRSkKcGxvdApwZGYocGFzdGUoIi4vZmlndXJlcy8iLCB0aXNzdWUsICIvIiwgdGlzc3VlLCAiX1VNQVBfY2x1c3RlcnNfbGFiZWxzLnBkZiIsIHNlcCA9ICIiKSkKcGxvdApkZXYub2ZmKCkKYGBgCgpNYXAgd2l0aCBTQ0lOQS1nZW5lcmF0ZWQgY2VsbC10eXBlIGxhYmVscwoKYGBge3J9CkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAic2NpbmFfbGFiZWxzX3JlZmluZWQiLCBsYWJlbCA9IFRSVUUpICYgTm9MZWdlbmQoKQpgYGAKCk1hcCB3aXRoIGdlbmVyYWwgY2VsbC10eXBlIGxhYmVscyBmb3IgcGFwZXIKCmBgYHtyfQpwbG90IDwtIERpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIsCiAgICAgICAgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUpICsKICBnZ3RpdGxlKE5VTEwpCnBsb3QKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9VTUFQX2dlbmVyYWxfY2VsbF9sYWJlbHMucGRmIiwgc2VwID0gIiIpLAogICAgaGVpZ2h0ID0gNywKICAgIHdpZHRoID0gOSkKcGxvdApkZXYub2ZmKCkKYGBgCgpNYXAgZ3JvdXBpbmcgYnkgZ2VuZXJhbCBjZWxsIHR5cGUgbGFiZWxzIGJ1dCB3aXRoIG5vIGxhYmVscyBvbiBwbG90CgpgYGB7cn0KcGxvdCA8LSBEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gImdlbmVyYWxfY2VsbF9sYWJlbHMiKSArCiAgZ2d0aXRsZShOVUxMKSAmCiAgTm9MZWdlbmQoKQpwbG90CnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfVU1BUF9nZW5lcmFsX2NlbGxfbGFiZWxzX25vTGFiZWxzLnBkZiIsIAogICAgICAgICAgc2VwID0gIiIpKQpwbG90CmRldi5vZmYoKQpgYGAKCk1hcCB3aXRoIG9yaWdpbmFsIGlkZW50aXRpZXMKCmBgYHtyfQpwbG90IDwtIERpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIsCiAgICAgICAgY29scyA9IGNhcnRvX3BhbChsZW5ndGgobGV2ZWxzKGFzLmZhY3Rvcihzb2JqJG9yaWcuaWRlbnQpKSksICJTYWZlIikpICsKICBnZ3RpdGxlKE5VTEwpCnBsb3QKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9VTUFQX29yaWdfaWRlbnRzLnBkZiIsIAogICAgICAgICAgc2VwID0gIiIpKQpwbG90CmRldi5vZmYoKQpgYGAKCkJhcnBsb3Qgd2l0aCBvcmlnaW5hbCBpZGVudGl0aWVzIG9uIGEgY2x1c3Rlci1sZXZlbCBncm91cGluZzoKCmBgYHtyfQojIE1ldGEgZGF0YSB0byBwbG90OgpkZiA8LSBzb2JqQG1ldGEuZGF0YQojIENoZWNrIHdoYXQgY29sdW1uIHRoZSBjbHVzdGVyIGlkZW50aXRpZXMgYXJlIGluCmNvbCA8LSB3aGljaChjb2xuYW1lcyhkZikgPT0gcmVzKQojIE9yZGVyIGNsdXN0ZXJzCmRmWyxjb2xdIDwtIGZhY3RvcihJZGVudHMoc29iaiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYyhzb3J0KGFzLm51bWVyaWMobGV2ZWxzKElkZW50cyhzb2JqKSkpKSkpCiMgQmFzaWMgcGxvdCBvZiBjbHVzdGVycyBieSByZXBsaWNhdGUKZ2dwbG90KGRmLCBhZXMoeCA9IGdldChyZXMpLCBmaWxsID0gb3JpZy5pZGVudCkpICsKICBnZW9tX2JhcigpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQojIFBsb3QgYXMgcHJvcG9ydGlvbiBvciBwZXJjZW50YWdlIG9mIGNsdXN0ZXIKZ2dwbG90KGRmLCBhZXMoeCA9IGdldChyZXMpLCBmaWxsID0gb3JpZy5pZGVudCkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCmBgYAoKQmFycGxvdCB3aXRoIG9yaWdpbmFsIGlkZW50aXRpZXMgb24gYSBncm91cGVkIGJ5IGdlbmVyYWwgY2VsbCBsYWJlbHM6CgpgYGB7cn0KZGYgPC0gc29iakBtZXRhLmRhdGEKcGxvdDEgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IGdlbmVyYWxfY2VsbF9sYWJlbHMsIGZpbGwgPSBvcmlnLmlkZW50KSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfY2FydG9fZChuYW1lID0gTlVMTCwgcGFsZXR0ZSA9ICJTYWZlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHlsYWIoIk51bWJlciBvZiBjZWxscyIpCnBsb3QxCnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfYmFycGxvdF9vcmlnX2lkZW50X2NvdW50cy5wZGYiLCAKICAgICAgICAgIHNlcCA9ICIiKSkKcGxvdDEKZGV2Lm9mZigpCiMgUGxvdCBhcyBwcm9wb3J0aW9uIG9yIHBlcmNlbnRhZ2Ugb2YgY2x1c3RlcgpwbG90MiA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gZ2VuZXJhbF9jZWxsX2xhYmVscywgZmlsbCA9IG9yaWcuaWRlbnQpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICBzY2FsZV9maWxsX2NhcnRvX2QobmFtZSA9IE5VTEwsIHBhbGV0dGUgPSAiU2FmZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB5bGFiKCJQcm9wb3J0aW9uIG9mIGNlbGxzIikKcGxvdDIKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9iYXJwbG90X29yaWdfaWRlbnRfcHJvcG9ydGlvbnMucGRmIiwgCiAgICAgICAgICBzZXAgPSAiIikpCnBsb3QyCmRldi5vZmYoKQpgYGAKCiMjIERvdHBsb3RzCgpHZW5lcmF0ZSBkb3RwbG90IHdpdGggc3BlY2lmaWMgbWFya2VycwoKYGBge3J9CkRvdFBsb3Qoc29iaiwKICAgICAgICBhc3NheSA9ICJTQ1QiLAogICAgICAgIGZlYXR1cmVzID0gYygiUFRQUkMiLCAiQ0FMQ1JMIiwgIk5LRzciLCAiQ0QzRSIsICJNQVJDTyIsICJMWVotMSIsICJDRDE5IiwgIk1TNEExIiwgIlNUQUIyIikKICAgICAgICApICsKICBnZ3RpdGxlKCJTZWxlY3QgZmVhdHVyZXMgZm9yIGxpdmVyIG1hcCIpCmBgYAoKIyMgSGVhdG1hcHMKCkNhbGN1bGF0ZSBtYXJrZXJzIGZvciBnZW5lcmFsIGNlbGwgbGFiZWxzIHRoZW4gcmVzZXQgcmVzb2x1dGlvbgoKYGBge3J9CklkZW50cyhzb2JqKSA8LSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIKc29ial9tYXJrZXJzIDwtIFJ1blByZXN0b0FsbChzb2JqLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQpzb2JqX21hcmtlcnMgJT4lCiAgICBncm91cF9ieShjbHVzdGVyKSAlPiUKICAgIHNsaWNlX21heChuID0gMiwgb3JkZXJfYnkgPSBhdmdfbG9nMkZDKQpJZGVudHMoc29iaikgPC0gcmVzCmBgYAoKU2F2ZSBtYXJrZXJzCgpgYGB7cn0KZ3JvdXBzID0gImdlbmVyYWxfY2VsbF9sYWJlbHMiCndyaXRlLnRhYmxlKHNvYmpfbWFya2VycywKICAgICAgICAgICAgZmlsZSA9IHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsCiAgICAgICAgICAgICAgICAgICAgICAgICB0aXNzdWUsICJfbWFya2Vyc18iLCBncm91cHMsICIudHN2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiksCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICBjb2wubmFtZXMgPSBUUlVFKQpgYGAKCkdlbmVyYXRlIGhlYXRtYXAgd2l0aCB0b3AgNSBtYXJrZXJzIGdyb3VwaW5nIGJ5IGdlbmVyYWwgY2VsbCB0eXBlcwoKYGBge3J9CiMgUmVtb3ZlIG1pa2FkbyBnZW5lcyBmcm9tIG1hcmtlciBsaXN0CnNvYmpfbWFya2VycyA8LSBzb2JqX21hcmtlcnNbZ3JlcCgibWlrYWRvIiwgcm93bmFtZXMoc29ial9tYXJrZXJzKSwgaW52ZXJ0ID0gVFJVRSksXQpzb2JqX21hcmtlcnMgJT4lCiAgICBncm91cF9ieShjbHVzdGVyKSAlPiUKICAgIHRvcF9uKG4gPSA1LCB3dCA9IGF2Z19sb2cyRkMpIC0+IHRvcAojIElmIGxpdmVyLCBzZWxlY3QgZmV3ZXIgY2VsbHMKaWYgKHRpc3N1ZSA9PSAibGl2ZXIiKSB7CiAgY2VsbHMgPC0gc2FtcGxlKGNvbG5hbWVzKHNvYmopLCBzaXplID0gMzAwMDApCn0gZWxzZSBpZiAodGlzc3VlID09ICJQQk1DIikgewogIGNlbGxzIDwtIGNvbG5hbWVzKHNvYmopCn0KRG9IZWF0bWFwKHNvYmosIGZlYXR1cmVzID0gdG9wJGdlbmUsIGdyb3VwLmJ5ID0gImdlbmVyYWxfY2VsbF9sYWJlbHMiLCBzaXplID0gMywgCiAgICAgICAgICBhbmdsZSA9IDkwLCBjZWxscyA9IGNlbGxzKSArCiAgTm9MZWdlbmQoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCmBgYAoKTWFrZSBQREYgb2YgaGVhdG1hcAoKYGBge3J9Cmdyb3VwcyA8LSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl9oZWF0bWFwXyIsIGdyb3VwcywgIi5wZGYiLCBzZXAgPSAiIiksCiAgICBoZWlnaHQgPSAxMSwKICAgIHdpZHRoID0gNykKRG9IZWF0bWFwKHNvYmosIGZlYXR1cmVzID0gdG9wJGdlbmUsIGdyb3VwLmJ5ID0gImdlbmVyYWxfY2VsbF9sYWJlbHMiLCBzaXplID0gMiwgCiAgICAgICAgICBhbmdsZSA9IDkwLCBjZWxscyA9IGNlbGxzKSArCiAgTm9MZWdlbmQoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCmRldi5vZmYoKQpgYGAKCgojIyBGZWF0dXJlIHBsb3RzCgpNYWtlIHNwZWNpZmljIHBsb3RzIHdpdGggc3BlY2lmaWMgZ2VuZXMuIFRoZSBnZW5lcyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBpbmNsdWRlOiAqUFRQUkMsIENBTENSTCwgTktHNywgQ0QzRSwgTUFSQ08sIExZWiwgQ0QxOSwgTVM0QTEsIFNUQUIyLCBBTEIsIENENCwgQ0Q4QSwgQ0xFQzRHLCBDRDVMLCBDMVFCLCBBQ1RBMiwgVldGLCBJR0xMNSwgQ0Q2OCouIENhbiBhbHNvIHBsb3QgaW4gaXRhbGljcy4KCmBgYHtyfQpnZW5lQ29kZSA8LSAic2N0X0xZWi0xIiAjIFdvb2RjaHVjay1zcGVjaWZpYyBub21lbmNsYXR1cmUgZm9yIHRoaXMgZ2Vub21lCmdlbmUgPC0gIkxZWiIKbWFwVHlwZSA8LSAiTGl2ZXIiCkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gZ2VuZUNvZGUpICsKICBnZ3RpdGxlKHBhc3RlKGdlbmUsICItIiwgbWFwVHlwZSwgIm1hcCIpKQpGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IGdlbmVDb2RlKSArCiAgZ2d0aXRsZShicXVvdGUofml0YWxpYyguKGdlbmUpKSkpCmBgYAoKQW5vdGhlciB2ZXJzaW9uIG9mIHRoZSBmZWF0dXJlIHBsb3QgdGhhdCBvdXRwdXRzIGdlbmVzIGluIGl0YWxpY3MKCmBgYHtyfQppZiAodGlzc3VlID09ICJQQk1DIikgewogZ2VuZUNvZGVzIDwtIGMoInNjdF9QVFBSQyIsInNjdF9OS0c3Iiwic2N0X0NEMTQiLAogICAgICAgICAgICAgICAic2N0X0NEM0UiLCJzY3RfTUFSQ08iLCJzY3RfTFlaLTEiLAogICAgICAgICAgICAgICAic2N0X0NEMTkiLCJzY3RfTVM0QTEiLCJzY3RfU1RBQjIiLAogICAgICAgICAgICAgICAic2N0X0NENCIsInNjdF9DRDhBIiwgInNjdF9YQ0wxO1hDTDIiLAogICAgICAgICAgICAgICAic2N0X0NENUwiLCJzY3RfQzFRQiIsICJzY3RfTEVGMSIsCiAgICAgICAgICAgICAgICJzY3RfQUNUQTIiLCJzY3RfVldGIiwic2N0X0lHTEw1LTEiLAogICAgICAgICAgICAgICAic2N0X0NENjgiLCJzY3RfRkNHUjNBO0ZDR1IzQiIsInNjdF9UT1AyQSIpCiBnZW5lcyA8LSBjKCJQVFBSQyIsIk5LRzciLCJDRDE0IiwiQ0QzRSIsIk1BUkNPIiwiTFlaIiwKICAgICAgICAgICAiQ0QxOSIsIk1TNEExIiwiU1RBQjIiLCJDRDQiLCJDRDhBIiwgIlhDTDE7WENMMiIsCiAgICAgICAgICAgIkNENUwiLCJDMVFCIiwiTEVGMSIsIkFDVEEyIiwiVldGIiwiSUdMTDUiLCJDRDY4IiwKICAgICAgICAgICAiRkNHUjNBO0ZDR1IzQiIsIlRPUDJBIikgCn0gZWxzZSBpZiAodGlzc3VlID09ICJsaXZlciIpIHsKICBnZW5lQ29kZXMgPC0gYygic2N0X1B0cHJjIiwic2N0X0NBTENSTCIsInNjdF9OS0c3IiwKICAgICAgICAgICAgICAgICAic2N0X0NEM0UiLCJzY3RfTUFSQ08iLCJzY3RfTFlaLTEiLAogICAgICAgICAgICAgICAgICJzY3RfQ0QxOSIsInNjdF9NUzRBMSIsInNjdF9TVEFCMiIsCiAgICAgICAgICAgICAgICAgInNjdF9BTEItMSIsInNjdF9DRDQiLCJzY3RfQ0Q4QSIsCiAgICAgICAgICAgICAgICAgInNjdF9DTEVDNEciLCJzY3RfQ0Q1TCIsInNjdF9DMVFCIiwKICAgICAgICAgICAgICAgICAic2N0X0FDVEEyIiwic2N0X1ZXRiIsInNjdF9JR0xMNS0xIiwKICAgICAgICAgICAgICAgICAic2N0X0NENjgiLCJzY3RfWENMMTtYQ0wyIiwic2N0X0xFRjEiLAogICAgICAgICAgICAgICAgICJzY3RfUlNQTzMiLCJzY3RfTUVDT00iKQogIGdlbmVzIDwtIGMoIlBUUFJDIiwiQ0FMQ1JMIiwiTktHNyIsIkNEM0UiLCJNQVJDTyIsIkxZWiIsCiAgICAgICAgICAgICAiQ0QxOSIsIk1TNEExIiwiU1RBQjIiLCJBTEIiLCJDRDQiLCJDRDhBIiwKICAgICAgICAgICAgICJDTEVDNEciLCJDRDVMIiwiQzFRQiIsIkFDVEEyIiwiVldGIiwiSUdMTDUiLCJDRDY4IiwKICAgICAgICAgICAgICJYQ0wxO1hDTDIiLCJMRUYxIiwiUlNQTzMiLCJNRUNPTSIpIAp9CmZvcihudW0gaW4gMjpsZW5ndGgoZ2VuZUNvZGVzKSkgewogIHBsb3QgPC0gRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZUNvZGVzW251bV0pICsKICAgIGdndGl0bGUoYnF1b3RlKH5pdGFsaWMoLihnZW5lc1tudW1dKSkpKQogIHByaW50KHBsb3QpCiAgcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl8iLCBnZW5lc1tudW1dLCAiX1VNQVAucGRmIiwgc2VwID0gIiIpKQogIHByaW50KHBsb3QpCiAgZGV2Lm9mZigpCn0KYGBgCgojIyMgQ2VsbC1wb3B1bGF0aW9uLXNwZWNpZmljIG1hcmtlcnMKClBsb3QgbWFya2VyIGdlbmVzIGZvciBzcGVjaWZpYyBjZWxsIHBvcHVsYXRpb25zCgpFbmRvdGhlbGlhbCBjZWxsczoKCmBgYHtyfQpnZW5lQ29kZXMgPC0gYygic2N0X1NUQUIyIiwic2N0X0lUR0ExIiwic2N0X0NENTUiLCJzY3RfTFlWRTEiLAogICAgICAgICAgICAgICAic2N0X0NEMzQiLCJzY3RfVldGIiwic2N0X0lGSVRNMztJRklUTTI7SUZJVE0xIiwic2N0X1JTUE8zIiwKICAgICAgICAgICAgICAgInNjdF9NRUNPTSIsInNjdF9NZWNvbSIsInNjdF9DQUxDUkwiLCJzY3RfTE9DMTE0MDg5NjU0IiwKICAgICAgICAgICAgICAgInNjdF9SQU1QMiIsInNjdF9CU1QyIiwic2N0X0NMRUM0RyIsInNjdF9DVFNWO0NUU0wiLAogICAgICAgICAgICAgICAic2N0X1NUQUIxIiwic2N0X1BMQUM5Iiwic2N0X1BFQ0FNMSIsInNjdF9XTlQyIiwKICAgICAgICAgICAgICAgInNjdF9NWUw2Iiwic2N0X05SMkYyIikKZ2VuZXMgPC0gYygiU1RBQjIiLCJJVEdBMSIsIkNENTUiLCJMWVZFMSIsCiAgICAgICAgICAgIkNEMzQiLCJWV0YiLCJJRklUTTMiLCJSU1BPMyIsCiAgICAgICAgICAgIk1FQ09NIiwiTWVjb20iLCJDQUxDUkwiLCJMT0MxMTQwODk2NTQiLAogICAgICAgICAgICJSQU1QMiIsIkJTVDIiLCJDTEVDNEciLCJDVFNWO0NUU0wiLAogICAgICAgICAgICJTVEFCMSIsIlBMQUM5IiwiUEVDQU0xIiwiV05UMiIsCiAgICAgICAgICAgIk1ZTDYiLCJOUjJGMiIpIApmb3IobnVtIGluIDE6bGVuZ3RoKGdlbmVDb2RlcykpIHsKICBwbG90IDwtIEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVDb2Rlc1tudW1dKSArCiAgICBnZ3RpdGxlKGJxdW90ZSh+aXRhbGljKC4oZ2VuZXNbbnVtXSkpKSkKICBwcmludChwbG90KQogIHBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgZ2VuZXNbbnVtXSwgIl9VTUFQLnBkZiIsIHNlcCA9ICIiKSkKICBwcmludChwbG90KQogIGRldi5vZmYoKQp9CmBgYAoKTHltcGhvY3l0ZXM6CgpgYGB7cn0KZ2VuZUNvZGVzIDwtIGMoInNjdF9DRDNEIiwic2N0X0NEM0UiLCJzY3RfQ0Q4QSIsInNjdF9OS0c3IiwKICAgICAgICAgICAgICAgInNjdF9LTFJEMSIsInNjdF9LTFJCMSIsInNjdF9HWk1BIiwic2N0X0xFRjEiLAogICAgICAgICAgICAgICAic2N0X0lMN1ItMSIsInNjdF9FT01FUyIsInNjdF9USUdJVCIsInNjdF9YQ0wxO1hDTDIiLAogICAgICAgICAgICAgICAic2N0X1RPWCIsInNjdF9DVExBNCIsInNjdF9DRDQiLCJzY3RfR1pNSyIpCmdlbmVzIDwtIGMoIkNEM0QiLCJDRDNFIiwiQ0Q4QSIsIk5LRzciLAogICAgICAgICAgICJLTFJEMSIsIktMUkIxIiwiR1pNQSIsIkxFRjEiLAogICAgICAgICAgICJJTDdSIiwiRU9NRVMiLCJUSUdJVCIsIlhDTDE7WENMMiIsCiAgICAgICAgICAgIlRPWCIsIkNUTEE0IiwiQ0Q0IiwiR1pNSyIpIApmb3IobnVtIGluIDE6bGVuZ3RoKGdlbmVDb2RlcykpIHsKICBwbG90IDwtIEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGdlbmVDb2Rlc1tudW1dKSArCiAgICBnZ3RpdGxlKGJxdW90ZSh+aXRhbGljKC4oZ2VuZXNbbnVtXSkpKSkKICBwcmludChwbG90KQogIHBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgZ2VuZXNbbnVtXSwgIl9VTUFQLnBkZiIsIHNlcCA9ICIiKSkKICBwcmludChwbG90KQogIGRldi5vZmYoKQp9CmBgYAoKTWVzZW5jaHltZToKCmBgYHtyfQpnZW5lQ29kZXMgPC0gYygic2N0X0hISVAiLCJzY3RfQ09MMUEyIiwic2N0X0NPTDNBMSIsInNjdF9JR0ZCUDciLAogICAgICAgICAgICAgICAic2N0X0lHRkJQMyIsInNjdF9EQ04iLCJzY3RfQ09MMUExIiwic2N0X1NQQVJDIiwKICAgICAgICAgICAgICAgInNjdF9SQlAxIiwgInNjdF9DQUxDUkwiKQpnZW5lcyA8LSBjKCJISElQIiwiQ09MMUEyIiwiQ09MM0ExIiwiSUdGQlA3IiwKICAgICAgICAgICAiSUdGQlAzIiwiRENOIiwiQ09MMUExIiwiU1BBUkMiLAogICAgICAgICAgICJSQlAxIiwiQ0FMQ1JMIikgCmZvcihudW0gaW4gMTpsZW5ndGgoZ2VuZUNvZGVzKSkgewogIHBsb3QgPC0gRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZUNvZGVzW251bV0pICsKICAgIGdndGl0bGUoYnF1b3RlKH5pdGFsaWMoLihnZW5lc1tudW1dKSkpKQogIHByaW50KHBsb3QpCiAgcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl8iLCBnZW5lc1tudW1dLCAiX1VNQVAucGRmIiwgc2VwID0gIiIpKQogIHByaW50KHBsb3QpCiAgZGV2Lm9mZigpCn0KYGBgCgpMb29rIGF0IHpvbmF0aW9uIGdlbmUgc2lnbmF0dXJlczoKCmBgYHtyfQpjdl9nZW5lcyA8LSBjKCJGRVRVQiIsIkhNR0NTMSIsIkNZUDJFMSIsIkdMVUQxO0dMVUQyIiwiQ1lQMUEyIiwKICAgICAgICAgICAgICAiUkdOIiwiSU5NVCIsIkNPTVQiLCJGRFBTIiwiU1BSLTEiKQpjdl9nZW5lcwpwcF9nZW5lcyA8LSBjKCJTYWEyO1NhYTEtMSIsIkhBTVAiLCJBUE9BMSIsIkFQT0MyIiwiQ1JZTDEiLAogICAgICAgICAgICAgICJBTVkxQTtBTVkxQztBTVkxQjtBTVkyQTtBTVkyQiIsIk1ULUFUUDYiLCJVUk9DMSIsCiAgICAgICAgICAgICAgIkFQT0EyIiwiTVQtQ08zIikKcHBfZ2VuZXMKYGBgCgoKIyMgQ29ycmVsYXRpb24gcGxvdHMKCkdlbmVyYXRlIGhlYXRtYXBzIGNvbXBhcmluZyB3b29kY2h1Y2sgY2x1c3RlcnMgd2l0aCB2YXJpb3VzIGRhdGFzZXRzCgojIyMgU2V0dXAgZm9yIGFsbCBjb3JyZWxhdGlvbnMKCkZpcnN0LCBzZXQgdXAgd2hhdGV2ZXIgd29vZGNodWNrIGRhdGFzZXQgSSBhbSB3b3JraW5nIHdpdGggYnkgcmVhZGluZyBpbiB0aGUgb3J0aG9sb2cgdGFibGUsIGNob29zaW5nIHdoZXRoZXIgdGhlIG9ydGhvbG9ncyB0byB1c2UgYXJlIGh1bWFuLCBtb3VzZSwgb3Igd29vZGNodWNrLCBhbmQgY2FsY3VsYXRpbmcgdGhlIGF2ZXJhZ2UgZXhwcmVzc2lvbiBmb3IgZWFjaCBjbHVzdGVyLiBUaGUgb3V0cHV0IG9mIHRoaXMgc2VjdGlvbiBpcyB0aGUgc2NhbGVkIGNsdXN0ZXIgZ2VuZS1leHByZXNzaW9uIG1hdHJpeAoKYGBge3J9Cmdyb3VwcyA8LSAiZ2VuZXJhbF9jZWxsX2xhYmVscyIKIyBSZWFkIGluIG9ydGhvbG9nIHRhYmxlCmdlbmVOYW1lVGFibGUgPC0gcmVhZC50YWJsZSgifi9Ecm9wYm94L1pvZS9zY2ZfdmVyc2lvbi9tYWtlX2d0Zi9vcnRob2ZpbmRlcl9zYzIvaG9tb2xvZ2VuZS9jb2xsZWN0ZWRPcnRob2ZpbmRlclBhaXJpbmdzLnRzdiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSkKd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAic2NhbGUuZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9IGdyb3VwcykKIyBTY2FsZSBkYXRhCndvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QgPC0gbmEub21pdCh0KHNjYWxlKHQoYXMubWF0cml4KHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcyBmcm9tIFNldXJhdCBvYmplY3QKdW5pcXVlSGllciA8LSByb3cubmFtZXMod29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzJFNDVCkKdW5pcXVlSGllciA8LSBhcy5kYXRhLmZyYW1lKHVuaXF1ZUhpZXIpCiMgQmluZCB3aXRoIGdlbmVOYW1lVGFibGUgdG8gZ2V0IGNvcnJlY3Qgb3JkZXIgKG5vdGljZSB1bmlxdWVIaWVyIGlzIG9uIGxlZnQpCm5ld05hbWVzIDwtIGRwbHlyOjpsZWZ0X2pvaW4odW5pcXVlSGllciwgZ2VuZU5hbWVUYWJsZSwgYnkgPSAidW5pcXVlSGllciIpCiMgR2V0IG9ydGhvbG9ncyBmcm9tIGVpdGhlciBtb3VzZSBvciBodW1hbgpzcGVjaWVzIDwtICJodW1hbiIKaWYgKHNwZWNpZXMgPT0gImh1bWFuIikgewogICMgSWYgaHVtYW4gb25lLXRvLW9uZSBvcnRobyBoYXMgTkEsIHJlcGxhY2Ugd2l0aCBtaWthZG9fZmluYWxfc2MyX3N0cmluZ2VudF9ub01pdG9fcHJvdGVpbiBjb2x1bW4KICAjIFRoaXMgaXMgdG8gYXZvaWQgYW5kIHBvdGVudGlhbCBtaXN0YWtlcyBpbiByZWNvZ25pemluZyB0aGluZ3MgaXQgc2hvdWxkbid0IGJlIHJlY29nbml6aW5nCiAgbmV3TmFtZXMkc3BlY2llc09uZVRvT25lIDwtIGlmZWxzZShpcy5uYShuZXdOYW1lcyRodW1hbk9uZVRvT25lKSwgbmV3TmFtZXMkdW5pcXVlSGllciwgbmV3TmFtZXMkaHVtYW5PbmVUb09uZSkKfSBlbHNlIGlmIChzcGVjaWVzID09ICJtb3VzZSIpIHsKICBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUgPC0gaWZlbHNlKGlzLm5hKG5ld05hbWVzJG1vdXNlT25lVG9PbmUpLCBuZXdOYW1lcyR1bmlxdWVIaWVyLCBuZXdOYW1lcyRtb3VzZU9uZVRvT25lKQp9IGVsc2UgaWYgKHNwZWNpZXMgPT0gIndvb2RjaHVjayIpIHsKICBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUgPC0gbmV3TmFtZXMkdW5pcXVlSGllcgp9CiMgR3JhYiBkYXRhZnJhbWUKd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzIDwtIHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyRTQ1QKIyBSZXBsYWNlIG5hbWVzIHdpdGggb25lLXRvLW9uZSBvcnRob2xvZ3VlIG9mIHBhcnRpY3VsYXIgc3BlY2llcwpyb3cubmFtZXMod29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzKSA8LSBuZXdOYW1lcyRzcGVjaWVzT25lVG9PbmUKIyBNYWtlIHN1cmUgZm9ybWF0dGVkIGNvcnJlY3RseQp3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMgPC0gYXMuZGF0YS5mcmFtZSh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpCiMgT3JkZXIgYnkgZ2VuZSBuYW1lCndvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcyA8LSB3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXNbb3JkZXIocm93Lm5hbWVzKHdvb2RjaHVja0NsdXN0ZXJBdmVyYWdlcykpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZCh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpCmBgYAoKIyMjIERhdGFzZXQtc3BlY2lmaWMgc2V0dXAKCkNvcnJlbGF0aW9uIG9mIHdvb2RjaHVjayBQQk1DcyB3aXRoIGh1bWFuIDY4ayBQQk1DIGRhdGFzZXQgZnJvbSAxMFggR2Vub21pY3MKCmBgYHtyfQojIE5vdyBuZWVkIHRvIHJlYWQgaW4gNjhLIFBCTUMgZGF0YQpodW1hblBCTUMgPC0gcmVhZC5jc3YoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvY29ycmVsYXRpb25UZXN0cy82OEtfcGJtY19kYXRhLzY4S19lbnJpY2hlZEdlbmVzLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBGQUxTRSkKIyBHZXQgcmlkIG9mIHRvcCByb3cKaHVtYW5QQk1DIDwtIGh1bWFuUEJNQ1stMSxdCiMgU2VwYXJhdGUgYWxsIGNlbGwgYW5kIG15bG9pZCBjZWxsIGRhdGEKYWxsQ2VsbHMgPC0gc2VsZWN0KGh1bWFuUEJNQywgVjEsIFYyLCBWMykKbXllbG9pZCA8LSBzZWxlY3QoaHVtYW5QQk1DLCBWNSwgVjYsIFY3KQojIFJlbmFtZSBhbmQgZ2V0IHJpZCBvZiBmaXJzdCByb3cKY29sbmFtZXMoYWxsQ2VsbHMpIDwtIGMoIkNsdXN0ZXIiLCAiR2VuZSIsICJFbnJpY2htZW50IikKY29sbmFtZXMobXllbG9pZCkgPC0gYygiQ2x1c3RlciIsICJHZW5lIiwgIkVucmljaG1lbnQiKQojIEdldCByaWQgb2YgdG9wIHJvdwphbGxDZWxscyA8LSBhbGxDZWxsc1stMSxdCm15ZWxvaWQgPC0gbXllbG9pZFstMSxdCiMgSSBjYW4gdGhlbiBmaWx0ZXIgdGhlIHJvd3MgYW5kIGJpbmQgdGhlIGRhdGEgZnJhbWVzIGJhY2sgdG9nZXRoZXIgYnkgZ2VuZSBuYW1lCmZvciAoaiBpbiAxOjEwKSB7CiAgZGF0IDwtIGRwbHlyOjpmaWx0ZXIoYWxsQ2VsbHMsIENsdXN0ZXIgPT0gaikKICAjZGF0IDwtIGdldChwYXN0ZSgiYWxsQ2VsbHMiLCBqLCBzZXAgPSAiIikpCiAgIyBNdWx0aXBseSBlbnJpY2htZW50IHZhbHVlcyBieSAtMSBiZWNhdXNlIHRoZSBzaWducyBhcmUgYmFja3dhcmRzPz8/CiAgZGF0JEVucmljaG1lbnQgPC0gYXMubnVtZXJpYyhkYXQkRW5yaWNobWVudCkgKiAtMQogIGRhdCA8LSBkcGx5cjo6c2VsZWN0KGRhdCwgR2VuZSwgRW5yaWNobWVudCkKICBjb2xuYW1lcyhkYXQpIDwtIGMoIkdlbmUiLCBwYXN0ZSgiRW5yaWNobWVudCIsIGosIHNlcCA9ICIiKSkKICBpZiAoaiA9PSAxKSB7CiAgICBhbGxDZWxsc01hdHJpeCA8LSBkYXQKICB9CiAgZWxzZSB7CiAgICBhbGxDZWxsc01hdHJpeCA8LSBkcGx5cjo6ZnVsbF9qb2luKGFsbENlbGxzTWF0cml4LCBkYXQsIGJ5ID0gIkdlbmUiKQogIH0KfQojIE1ha2Ugcm93IG5hbWVzIGdlbmUgbmFtZXMKcm93bmFtZXMoYWxsQ2VsbHNNYXRyaXgpIDwtIGFsbENlbGxzTWF0cml4JEdlbmUKYWxsQ2VsbHNNYXRyaXggPC0gZHBseXI6OnNlbGVjdChhbGxDZWxsc01hdHJpeCwgLUdlbmUpCiMgTWFrZSBjb2x1bW4gbmFtZXMgY2VsbCB0eXBlcwpjb2xuYW1lcyhhbGxDZWxsc01hdHJpeCkgPC0gYygiQWN0aXZhdGVkIENEOCsiLCAiTmFpdmUgQ0Q4KyIsICJNZW1vcnkgYW5kIFJlZyBUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5haXZlIENENCsiLCAiTksiLCAiQ0Q4KyIsICJCIiwgIk1lZ2FrYXJ5b2N5dGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1vbm9jeXRlcyBhbmQgRGVuZHJpdGljIiwgIkIsIERlbmRyaXRpYywgVCIpCiMgU2NhbGUgYWNyb3NzIGNvbHVtbnMKYWxsQ2VsbHNNYXRyaXggPC0gdChzY2FsZSh0KGFsbENlbGxzTWF0cml4KSkpCiMgT3JkZXIgZ2VuZXMgYWxwaGFiZXRpY2FsbHkgYnkgZ2VuZSBuYW1lCmFsbENlbGxzTWF0cml4IDwtIGFsbENlbGxzTWF0cml4W29yZGVyKHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCkpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZChhbGxDZWxsc01hdHJpeCkKc3BlY2llc0RhdGEgPC0gIjY4S1BCTUMiCmBgYAoKQ29ycmVsYXRpb24gb2Ygd29vZGNodWNrIGxpdmVyIHdpdGggaHVtYW4gbGl2ZXIgZGF0YXNldCBmcm9tIE1hY1BhcmxhbmQgKmV0IGFsLiogKDIwMTgpCgpgYGB7cn0KIyBGaW5kIGNsdXN0ZXIgYXZlcmFnZXMgb2YgaHVtYW4gbGl2ZXIgZGF0YQpsb2FkKCJ+L0Ryb3Bib3gvWm9lL3NjZl92ZXJzaW9uL2FuYWx5c2lzL2NvcnJlbGF0aW9uVGVzdHMvSHVtYW5MaXZlci5SRGF0YSIpCiMgUnVuIFNDVHJhbnNmb3JtCkh1bWFuTGl2ZXJTZXVyYXQgPC0gVXBkYXRlU2V1cmF0T2JqZWN0KEh1bWFuTGl2ZXJTZXVyYXQpCkh1bWFuTGl2ZXJTZXVyYXQgPC0gU0NUcmFuc2Zvcm0oSHVtYW5MaXZlclNldXJhdCkKaHVtYW5DbHVzdGVyQXZlcmFnZXMgPC0gQXZlcmFnZUV4cHJlc3Npb24oSHVtYW5MaXZlclNldXJhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXlzID0gIlNDVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSAic2NhbGUuZGF0YSIpCiMgUmVwbGFjZSBjbHVzdGVyIG51bWJlcnMgd2l0aCBuYW1lcwpjb2xuYW1lcyhodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpIDwtIGMoIkhlcCAxIiwgIkFscGhhLWJldGEgVCBjZWxscyIsICJIZXAgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW5mbGFtbWF0b3J5IG1hY3MiLCAiSGVwIDMiLCAiSGVwIDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBsYXNtYSBjZWxscyIsICJOSy1saWtlIGNlbGxzIiwgIkdhbW1hLWRlbHRhIFQgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1pbmZsYW1tYXRvcnkgbWFjcyIsICJQZXJpcG9ydGFsIExTRUNzIiwgIkNlbnRyYWwgdmVub3VzIExTRUNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3J0YWwgZW5kb3RoZWxpYWwgY2VsbHMiLCAiSGVwIDUiLCAiSGVwIDYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hdHVyZSBCIGNlbGxzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkdhbW1hLWRlbHRhIFQgY2VsbHMgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXJ5dGhyb2lkIGNlbGxzIiwgIkhlcGF0aWMgc3RlbGxhdGUgY2VsbHMiKQojIElmIG9ubHkgbG9va2luZyBhdCBzcGVjaWZpYyBjbHVzdGVycwojaHVtYW5DbHVzdGVyQXZlcmFnZXMkU0NUIDwtIGh1bWFuQ2x1c3RlckF2ZXJhZ2VzJFNDVFssYygiMyIsIjEiLCIxNSIsIjYiLCIxNCIsIjUiKV0KIyBPdGhlcndpc2UgZ28gc3RyYWlnaHQgdG8gaGVyZToKaHVtYW5DbHVzdGVyQXZlcmFnZXMkU0NUIDwtIG5hLm9taXQodChzY2FsZSh0KGFzLm1hdHJpeChodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcwpodW1hbkdlbmVzIDwtIHJvdy5uYW1lcyhodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpCiMgTm93IHR1cm4gaW50byBsYXJnZSBkYXRhZnJhbWUKYWxsQ2VsbHNNYXRyaXggPC0gYXMuZGF0YS5mcmFtZShodW1hbkNsdXN0ZXJBdmVyYWdlcyRTQ1QpCiMgT3JkZXIgYnkgcm93IG5hbWUKYWxsQ2VsbHNNYXRyaXggPC0gYWxsQ2VsbHNNYXRyaXhbb3JkZXIocm93Lm5hbWVzKGFsbENlbGxzTWF0cml4KSksXQojIFNhbml0eSBjaGVjawpoZWFkKGFsbENlbGxzTWF0cml4KQpzcGVjaWVzRGF0YSA8LSAibWFjcGFybGFuZCIKYGBgCgpDb3JyZWxhdGlvbiBvZiB3b29kY2h1Y2sgbGl2ZXIgd2l0aCBodW1hbiBsaXZlciBkYXRhc2V0IGZyb20gQWl6YXJhbmkgKmV0IGFsLioKCmBgYHtyfQojIFJlYWQgaW4gQWl6YXJhbmkgZGF0YXNldAphaXphcmFuaSA8LSByZWFkUkRTKCJ+L0Ryb3Bib3gvWm9lL3NjZl92ZXJzaW9uL2FuYWx5c2lzL2NvcnJlbGF0aW9uVGVzdHMvR1NFMTI0Mzk1X05vcm1hbGh1bWFubGl2ZXJkYXRhLlJEYXRhIikKIyBSZWFkIGluIGNsdXN0ZXJzIGFuZCBsYWJlbCBjZWxscwphaXphcmFuaUNsdXN0ZXJzIDwtIHJlYWQudGFibGUoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvY29ycmVsYXRpb25UZXN0cy9HU0UxMjQzOTVfY2x1c3RlcnBhcnRpdGlvbi50eHQiKQojIE9ubHkga2VlcCBjZWxscyBpbiB0aGUgY2x1c3RlciBvYmplY3QKYWl6YXJhbmkgPC0gYWl6YXJhbmlbLGludGVyc2VjdChjb2xuYW1lcyhhaXphcmFuaSkscm93Lm5hbWVzKGFpemFyYW5pQ2x1c3RlcnMpKV0KIyBDcmVhdGUgU2V1cmF0IG9iamVjdAphaXphcmFuaSA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gYWl6YXJhbmkpCiMgUnVuIFNDVHJhbnNmb3JtCmFpemFyYW5pIDwtIFNDVHJhbnNmb3JtKGFpemFyYW5pKQojIEFkZCBjbHVzdGVyIElEcwpJZGVudHMoYWl6YXJhbmkpIDwtIGFpemFyYW5pQ2x1c3RlcnMkc2N0LmNwYXJ0CiMgR2V0IGNsdXN0ZXIgYXZlcmFnZXMKYWl6YXJhbmlBdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihhaXphcmFuaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiKQphaXphcmFuaUF2ZXJhZ2VzJFNDVCA8LSBuYS5vbWl0KHQoc2NhbGUodChhcy5tYXRyaXgoYWl6YXJhbmlBdmVyYWdlcyRTQ1QpKSkpKQojIEdyYWIgZ2VuZSBuYW1lcwphaXphcmFuaUdlbmVzIDwtIHJvdy5uYW1lcyhhaXphcmFuaUF2ZXJhZ2VzJFNDVCkKIyBOb3cgdHVybiBpbnRvIGxhcmdlIGRhdGFmcmFtZQphbGxDZWxsc01hdHJpeCA8LSBhcy5kYXRhLmZyYW1lKGFpemFyYW5pQXZlcmFnZXMkU0NUKQojIE9yZGVyIGJ5IGNvbHVtbgphbGxDZWxsc01hdHJpeCA8LSBhbGxDZWxsc01hdHJpeFssYXMuY2hhcmFjdGVyKHNvcnQoYXMubnVtZXJpYyhjb2xuYW1lcyhhbGxDZWxsc01hdHJpeCkpKSldCiMgUmVuYW1lIGNvbHVtbnMgdG8gYmUgbW9yZSBtZWFuaW5nZnVsIChub3QgdG90YWxseSBjb25maWRlbnQgSSBnb3QgYWxsIGNvcnJlY3QpCmNvbG5hbWVzKGFsbENlbGxzTWF0cml4KSA8LSBjKCdOSywgTktUIGFuZCBUIGNlbGxzICgxKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICgyKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICgzKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICg0KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICg1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICg2KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICg3KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCIGNlbGxzICg4KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMaXZlciBzaW51c29pZGFsIGVuZG90aGVsaWFsIGNlbGxzICg5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYWNyb3Zhc2N1bGFyIGVuZG90aGVsaWFsIGNlbGxzICgxMCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSGVwYXRvY3l0ZXMgKDExKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdOSywgTktUIGFuZCBUIGNlbGxzICgxMiknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTGl2ZXIgc2ludXNvaWRhbCBlbmRvdGhlbGlhbCBjZWxscyAoMTMpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hlcGF0b2N5dGVzICgxNCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnT3RoZXIgZW5kb3RoZWxpYWwgY2VsbHMgKDE1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciAoMTYpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hlcGF0b2N5dGVzICgxNyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTkssIE5LVCBhbmQgVCBjZWxscyAoMTgpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05LLCBOS1QgYW5kIFQgY2VsbHMgKDE5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMaXZlciBzaW51c29pZGFsIGVuZG90aGVsaWFsIGNlbGxzICgyMCknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTWFjcm92YXNjdWxhciBlbmRvdGhlbGlhbCBjZWxscyAoMjEpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0IgY2VsbHMgKDIyKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdLdXBmZmVyIGNlbGxzICgyMyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRVBDQU0rIGNlbGxzIGFuZCBjaG9sYW5naW9jeXRlcyAoMjQpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0t1cGZmZXIgY2VsbHMgKDI1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciBlbmRvdGhlbGlhbCBjZWxscyAoMjYpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ090aGVyICgyNyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTkssIE5LVCBhbmQgVCBjZWxscyAoMjgpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01hY3JvdmFzY3VsYXIgZW5kb3RoZWxpYWwgY2VsbHMgKDI5KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdIZXBhdG9jeXRlcyAoMzApJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0t1cGZmZXIgY2VsbHMgKDMxKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYWNyb3Zhc2N1bGFyIGVuZG90aGVsaWFsIGNlbGxzICgzMiknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU3RlbGxhdGUgY2VsbHMgYW5kIG15b2ZpYnJvYmxhc3RzICgzMyknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQiBjZWxscyAoMzQpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ090aGVyIGVuZG90aGVsaWFsIGNlbGxzICgzNSknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnT3RoZXIgKDM2KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlciAoMzcpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0IgY2VsbHMgKDM4KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdFUENBTSsgY2VsbHMgYW5kIGNob2xhbmdpb2N5dGVzICgzOSknKQojIE9yZGVyIGJ5IHJvdyBuYW1lCmFsbENlbGxzTWF0cml4IDwtIGFsbENlbGxzTWF0cml4W29yZGVyKHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCkpLF0KIyBTYW5pdHkgY2hlY2sKaGVhZChhbGxDZWxsc01hdHJpeCkKc3BlY2llc0RhdGEgPC0gImFpemFyYW5pIgpgYGAKCkNvcnJlbGF0aW9uIG9mIHdvb2RjaHVjayBsaXZlciB3aXRoIHdvb2RjaHVjayBQQk1Dcy4gRm9yIHRoaXMgY29ycmVsYXRpb24sIHJlYWQgaW4gdGhlIHdvb2RjaHVjayBsaXZlciBkYXRhc2V0IGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhpcyBzY3JpcHQgYW5kIHRoZW4gcmVhZCBpbiB0aGUgd29vZGNodWNrIFBCTUNzIGJlbG93CgpgYGB7cn0KZ3JvdXBzIDwtICJnZW5lcmFsX2NlbGxfbGFiZWxzIgojIFN0YXJ0IHdpdGggbGl2ZXIgYW5kIHJlYWQgaW4gd29vZGNodWNrIFBCTUNzIGFnYWluCmxvYWQoIn4vRHJvcGJveC9ab2Uvc2NmX3ZlcnNpb24vYW5hbHlzaXMvaGVhbHRoeV9zYy9zZXVyYXRfb2JqZWN0cy9ub19kcm9wbGV0UUMvaW50ZWdyYXRlZF9QQk1DX2NjYV9rYW5jaG9yNV9zY0NsdXN0Vml6LlJEYXRhIikKSWRlbnRzKHNjU2V1cmF0KSA8LSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuNiIKIyBGaW5kIGNsdXN0ZXIgYXZlcmFnZXMKcGJtY0NsdXN0ZXJBdmVyYWdlcyA8LSBBdmVyYWdlRXhwcmVzc2lvbihzY1NldXJhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gZ3JvdXBzKQpwYm1jQ2x1c3RlckF2ZXJhZ2VzIDwtIGFzLmRhdGEuZnJhbWUobmEub21pdCh0KHNjYWxlKHQoYXMubWF0cml4KHBibWNDbHVzdGVyQXZlcmFnZXMkU0NUKSkpKSkpCiMgT3JkZXIgYnkgcm93IG5hbWUKYWxsQ2VsbHNNYXRyaXggPC0gcGJtY0NsdXN0ZXJBdmVyYWdlc1tvcmRlcihyb3cubmFtZXMocGJtY0NsdXN0ZXJBdmVyYWdlcykpLF0Kc3BlY2llc0RhdGEgPC0gIlBCTUMiCmBgYAoKIyMjIE91dHB1dCBwbG90cyBmb3IgYWxsIGNvcnJlbGF0aW9ucwoKYGBge3J9CiMgTm93IGZpbmQgaW50ZXJzZWN0aW5nIGdlbmVzCm1hdGNoZXMgPC0gaW50ZXJzZWN0KHJvdy5uYW1lcyhhbGxDZWxsc01hdHJpeCksCiAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyh3b29kY2h1Y2tDbHVzdGVyQXZlcmFnZXMpKQojIExvb2sgYXQgaG93IG1hbnkgZ2VuZXMgbWF0Y2hlZApsZW5ndGgobWF0Y2hlcykKIyBNYWtlIG5ldyBtYXRyaWNlcyB3aXRoIG9ubHkgbWF0Y2hpbmcgZ2VuZSBuYW1lcwp0b0NvciA8LSBhbGxDZWxsc01hdHJpeFttYXRjaGVzLF0Kd29vZGNodWNrQXZlcmFnZXNDb3IgPC0gd29vZGNodWNrQ2x1c3RlckF2ZXJhZ2VzW21hdGNoZXMsXQojIERvIFBlYXJzb24KcGVhclZhbCA8LSBjb3IodG9Db3IsIHdvb2RjaHVja0F2ZXJhZ2VzQ29yLCBtZXRob2QgPSAicGVhcnNvbiIpCmhlYXRtYXAocGVhclZhbCkKICAgICAgICAjbWFpbiA9IHBhc3RlKCJQZWFyc29uIGNvcnJlbGF0aW9uIG9mIiwgc3BlY2llc0RhdGEsICJ2cyIsIHdvb2RjaHVja0RhdGEpLAogICAgICAgICN4bGFiID0gd29vZGNodWNrRGF0YSwKICAgICAgICAjeWxhYiA9IHNwZWNpZXNEYXRhKQogICAgICAgICNtYXJnaW5zID0gYyg2LDExKSkKI1Jvd3YgPSBOQSwKI0NvbHYgPSBOQSkKcGRmKHBhc3RlKCIuL2ZpZ3VyZXMvIiwgdGlzc3VlLCAiLyIsIHRpc3N1ZSwgIl8iLCBzcGVjaWVzRGF0YSwgIl9QZWFyc29uQ29yLnBkZiIsIHNlcCA9ICIiKSwKICAgIGhlaWdodCA9IDEzLCB3aWR0aCA9IDEzKQpoZWF0bWFwKHBlYXJWYWwsIG1hcmdpbnMgPSBjKDEzLDEzKSkKZGV2Lm9mZigpCiMgRG8gU3BlYXJtYW4Kc3BlYXJWYWwgPC0gY29yKHRvQ29yLCB3b29kY2h1Y2tBdmVyYWdlc0NvciwgbWV0aG9kID0gInNwZWFybWFuIikKaGVhdG1hcChzcGVhclZhbCkKICAgICAgICAjbWFpbiA9IHBhc3RlKCJTcGVhcm1hbiBjb3JyZWxhdGlvbiBvZiIsIHNwZWNpZXNEYXRhLCAidnMiLCB3b29kY2h1Y2tEYXRhKSwKICAgICAgICAjeGxhYiA9IHdvb2RjaHVja0RhdGEsCiAgICAgICAgI3lsYWIgPSBzcGVjaWVzRGF0YSkKICAgICAgICAjbWFyZ2lucyA9IGMoNiwxMSkpCiNSb3d2ID0gTkEsCiNDb2x2ID0gTkEpCnBkZihwYXN0ZSgiLi9maWd1cmVzLyIsIHRpc3N1ZSwgIi8iLCB0aXNzdWUsICJfIiwgc3BlY2llc0RhdGEsICJfU3BlYXJtYW5Db3IucGRmIiwgc2VwID0gIiIpLAogICAgaGVpZ2h0ID0gMTMsIHdpZHRoID0gMTMpCmhlYXRtYXAoc3BlYXJWYWwsIG1hcmdpbnMgPSBjKDEzLDEzKSkKZGV2Lm9mZigpCmBgYAoKCgoK